#include "TarsThreadPool.h"

TarsThreadPool::TarsThreadPool():
    _threadNum(1),
    _bTerminate(true),
    _atomic(0)
{

}

TarsThreadPool::~TarsThreadPool()
{
    waitForAllDone(10);
    stop();
}

TarsThreadPool &TarsThreadPool::getInstance()
{
    static TarsThreadPool instance;
    return instance;
}

size_t TarsThreadPool::getThreadNum()
{
    unique_lock<mutex> lock(_mutex);
    return _threads.size();
}

size_t TarsThreadPool::getJobNum()
{
    unique_lock<mutex> lock(_mutex);
    return _tasks.size();
}

void TarsThreadPool::stop()
{
    if(_bTerminate)
    {
        return;
    }

    {
        unique_lock<mutex> lock(_mutex);

        _bTerminate = true;

        _condition.notify_all();
    }

    for (size_t i = 0; i < _threads.size(); i++)
    {
        if(_threads[i]->joinable())
        {
            _threads[i]->join();
        }
        delete _threads[i];
        _threads[i] = nullptr;
    }

    unique_lock<mutex> lock(_mutex);
    _threads.clear();
}

bool TarsThreadPool::init(size_t num)
{
    unique_lock<mutex> lock(_mutex);
    // 不为空表示已经初始化过了
    if(!_threads.empty())
    {
        // todo 加log 或者报异常
        return false;
    }

    // 确认线程数量
    _threadNum = num;
    return true;
}

bool TarsThreadPool::start()
{
    unique_lock<mutex> lock(_mutex);
    // 不为空表示已经初始化过了
    if(!_threads.empty())
    {
        // todo 加log
        return false;
    }

    // 设为启动标志
    _bTerminate = false;

    // 根据线程数量创建线程
    for(size_t i = 0; i < _threadNum; i++)
    {
        _threads.emplace_back(new thread(&TarsThreadPool::run, this));
    }
    return true;
}

bool TarsThreadPool::get(TarsThreadPool::TaskFuncPtr &task)
{
    unique_lock<mutex> lock(_mutex);
    if(_tasks.empty())
    {
        // 队列为空就进入休眠状态
        _condition.wait(lock, [this]{ return _bTerminate || !_tasks.empty(); });
    }

    // 判断是否为退出线程池的唤醒
    if(_bTerminate)
        return false;

    if(!_tasks.empty())
    {
        task = move(_tasks.front());
        _tasks.pop();
        return true;
    }

    return false;
}

void TarsThreadPool::run()
{
    while(!isTerminate())
    {
        TaskFuncPtr task;
        bool ok = get(task);    // 读取任务
        if(ok)
        {
            ++_atomic;
            try
            {
                if(task->_expireTime != 0 && task->_expireTime < TNOWMS)
                {
                    //超时任务，是否需要处理? 默认丢弃
                }
                else
                {
                    task->_func(); // 执行任务
                }
            }
            catch (...)
            {
                // 加log
            }
            --_atomic;

            // _atomic = 0：代表没有线程在执行任务
            // _tasks.empty(): 代表任务队列为空
            // 综合为: 任务都执行完毕了
            unique_lock<mutex> lock(_mutex);
            if (_atomic == 0 && _tasks.empty())
            {
                _condition.notify_all(); // 这里只是为了通知waitForAllDone
            }
        }
    }
}

bool TarsThreadPool::waitForAllDone(int millsecond)
{
    unique_lock<mutex> lock(_mutex);

    if (_tasks.empty())
        return true;

    if (millsecond < 0)
    {
        // 死等
        _condition.wait(lock, [this] { return _tasks.empty(); });
        return true;
    }
    else
    {
        // 超时等待
        return _condition.wait_for(lock, chrono::milliseconds(millsecond), [this] { return _tasks.empty(); });
    }
}

/////////////////////////时间类管理才对->这里只是偷个懒////////////////////////////////////
#ifdef WIN32
#include <windows.h>
#else
#include <sys/time.h>
#endif
int gettimeofday(struct timeval &tv)
{
#if WIN32
  time_t clock;
  struct tm tm;
  SYSTEMTIME wtm;
  GetLocalTime(&wtm);
  tm.tm_year  = wtm.wYear - 1900;
  tm.tm_mon  = wtm.wMonth - 1;
  tm.tm_mday  = wtm.wDay;
  tm.tm_hour  = wtm.wHour;
  tm.tm_min  = wtm.wMinute;
  tm.tm_sec  = wtm.wSecond;
tm. tm_isdst  = -1;
  clock = mktime(&tm);
  tv.tv_sec = clock;
  tv.tv_usec = wtm.wMilliseconds * 1000;
  return 0;
#else
  return ::gettimeofday(&tv, 0);
#endif
}

void getNow(timeval *tv)
{
#if TARGET_PLATFORM_IOS || TARGET_PLATFORM_LINUX
  int idx = _buf_idx;
  *tv = _t[idx];
  if(fabs(_cpu_cycle - 0) < 0.0001 && _use_tsc)
 {
    addTimeOffset(*tv, idx);
 }
  else
 {
    TC_Common::gettimeofday(*tv);
 }
#else
    gettimeofday(*tv);
#endif
}

uint64_t getNowMs()
{
    struct timeval tv;
    getNow(&tv);
    return tv.tv_sec * (int64_t)1000 + tv.tv_usec / 1000;
}

///////////////////此处是测试样例放在main内就行/////////////////////
#if 0
void func0()
{
  std::this_thread::sleep_for(std::chrono::seconds(5));
  cout << "func0()" << endl;
}

void func1(int a)
{
    std::this_thread::sleep_for(std::chrono::seconds(10));
    cout << "func1() a=" << a << endl;
}

void func2(int a, string b)
{
  cout << "func1() a=" << a << ", b=" << b<< endl;
}

void test1() // 简单测试线程池
{
    TarsThreadPool threadpool;
    threadpool.init(2);
    threadpool.start(); // 启动线程池
    // 假如要执行的任务
    threadpool.exec(1000,func0);
    threadpool.exec(func1, 10);
    threadpool.exec(func2, 20, "darren");
    threadpool.waitForAllDone();
    threadpool.stop();
}

int func1_future(int a)
{
    cout << "func1() a=" << a << endl;
    return a;
}

string func2_future(int a, string b)
{
    cout << "func1() a=" << a << ", b=" << b<< endl;
    return b;
}

void test2() // 测试任务函数返回值
{
    TarsThreadPool threadpool;
    threadpool.init(1);
    threadpool.start(); // 启动线程池
    // 假如要执行的任务
    std::future<decltype(func1_future(0))> result1 = threadpool.exec(func1_future, 10);
    std::future<string> result2 = threadpool.exec(func2_future, 20, "darren");
    // auto result2 = threadpool.exec(func2_future, 20, "darren");
    std::cout << "result1: " << result1.get() << std::endl;
    std::cout << "result2: " << result2.get() << std::endl;
    threadpool.waitForAllDone();
    threadpool.stop();
}

class Test
{
public:
    int test(int i){
        cout << _name << ", i = " << i << endl;
        return i;
    }
    void setName(string name){
        _name = name;
    }
    string _name;
};

void test3() // 测试类对象函数的绑定
{
    TarsThreadPool threadpool;
    threadpool.init(1);
    threadpool.start(); // 启动线程池
    Test t1;
    Test t2;
    t1.setName("Test1");
    t2.setName("Test2");
    auto f1 = threadpool.exec(std::bind(&Test::test, &t1, std::placeholders::_1), 10);
    auto f2 = threadpool.exec(std::bind(&Test::test, &t2, std::placeholders::_1), 20);
    threadpool.waitForAllDone();
    cout << "t1 " << f1.get() << endl;
    cout << "t2 " << f2.get() << endl;
}

int main()
{
//    test1(); // 简单测试线程池
//    test2(); // 测试任务函数返回值
    test3(); // 测试类对象函数的绑定
    cout << "Hello World!" << endl;
    return 0;
}
#endif
